package com.hbwxz.Cas;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 模拟自旋锁
 * <p>
 * 自旋锁（spinlock）是指**尝试获取锁的线程不会立即阻塞，而是采用循环的方式去尝试获取锁，当线程发现锁被占用时，会不断循环判断锁的状态，直到获取。**这样的好处是减少线程上下文切换的消耗，缺点是循环会消耗CPU
 *
 * @author shenzw
 * @date 2023/12/20
 */
@Slf4j
public class SpinLockDemo {

    AtomicReference<Thread> threadAto = new AtomicReference();


    /**
     * 尝试获取锁（的时候自旋）
     */
    private void tryMyLock() {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + "\t" + "come in");
        while (!threadAto.compareAndSet(null, thread)) { // 获取锁失败，自旋

        }
    }

    /**
     * 释放锁
     */
    private void unMyLock() {
        Thread thread = Thread.currentThread();
        threadAto.compareAndSet(thread, null); // 如果是同一个锁，则释放锁
        System.out.println(thread.getName() + "\t" + "having unLock");
    }

    /**
     * ForkJoinPool.commonPool-worker-9	come in
     * ForkJoinPool.commonPool-worker-2	come in
     * ForkJoinPool.commonPool-worker-9	having unLock
     * ForkJoinPool.commonPool-worker-2	having unLock
     * <p>
     * 注意（有个坑！！！）：使用 CompletableFuture，要配合 Executors 线程池使用，不然使用默认线程池，主线程已结束就关闭线程池了
     *
     * @param args
     */
    public static void main(String[] args) {

        SpinLockDemo spinLockDemo = new SpinLockDemo();

        // 新建线程A
        CompletableFuture.runAsync(() -> {
            spinLockDemo.tryMyLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                spinLockDemo.unMyLock();
            }
        });

        // 主线程休眠1秒给线程A充足时间执行完
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 新建线程B
        CompletableFuture.runAsync(() -> {
            spinLockDemo.tryMyLock();
            spinLockDemo.unMyLock();
        });


        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


//        new Thread(() -> {
//            spinLockDemo.tryMyLock();
//            try {
//                TimeUnit.SECONDS.sleep(5);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            spinLockDemo.unMyLock();
//        }, "A").start();
//
//        // 暂停一会儿线程，保证A线程先于B线程启动并完成
//        try {
//            TimeUnit.SECONDS.sleep(1);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//
//        new Thread(() -> {
//            spinLockDemo.tryMyLock();
//            spinLockDemo.unMyLock();
//        }, "B").start();

    }

}
